import com.google.common.io.Files
import com.intellij.database.model.DasTable
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */

packageName = "com.sample;"
//db/java类型匹配模式
typeMapping = [
        (~/(?i)int/)                      : "long",
        (~/(?i)float|double|decimal|real/): "double",
        (~/(?i)decimal/): "BigDecimal",
        (~/(?i)datetime|timestamp/)       : "java.sql.Timestamp",
        (~/(?i)date/)                     : "java.sql.Date",
        (~/(?i)time/)                     : "java.sql.Time",
        (~/(?i)/)                         : "String"
]
//db规则匹配模式
dbTypeMapping = [
        (~/(?i)tinyint/)                  : "tinyint",
        (~/(?i)smallint/)                 : "smallint",
        (~/(?i)mediumint/)                : "mediumint",
        (~/(?i)bigint/)                   : "bigint",
        (~/(?i)int/)                      : "int",
        (~/(?i)float/)                    : "float",
        (~/(?i)double/)                   : "double",
        (~/(?i)decimal/)                  : "decimal",
        (~/(?i)real/)                     : "real",
        (~/(?i)decimal/)                  : "decimal",
        (~/(?i)timestamp/)                : "timestamp",
        (~/(?i)datetime/)                 : "datetime",
        (~/(?i)date/)                     : "date",
        (~/(?i)time/)                     : "time",
        (~/(?i)/)                         : "text"
]

dbUnsignedMapping = [
        (~/(?i)unsigned/)               : true
]
//定义常量
final FRONT_TYPE_SELECT_TREE = 'selectTree'
final FRONT_TYPE_SELECT = 'select'
final FRONT_TYPE_TEXT = 'text'
final FRONT_TYPE_NUMBER = 'number'
final FRONT_TYPE_DATE = 'date'
final FRONT_TYPE_DATE_TIME = 'datetime'
final FRONT_TYPE_TREE_SELECT = 'treeSelect'

FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
    SELECTION.filter { it instanceof DasTable }.each { generate(it, dir) }
}

def generate(table, dir) {
    def className = javaName(table.getName(), true)
    def fields = calcFields(table)
    def name = toStrikethrough(table.getName());
    def file = new File(dir, name);
    if(!file.exists()) {
        file.mkdirs()
    }

    //检查创建 components
    def componentsFile = new File(file, "components");
    if(!componentsFile.exists()) {
        componentsFile.mkdirs();
    }

    //检查创建 components
    def docsFile = new File(file, "docs");
    if(!docsFile.exists()) {
        docsFile.mkdirs();
    }

    //首页类型
    def frontHome = getTableFrontHome(table);

    //创建文档
    new File(docsFile, "index.md" ).withPrintWriter { out -> createDoc(out, name, className, fields, dir, table) }

    //创建model.js 文件
    new File(file, "model.js" ).withPrintWriter { out -> generate(out, name, className, fields, dir, table) }
    //创建 index.js
    new File(file, "index.js" ).withPrintWriter { out -> createIndexJs(out, name, className, fields, dir, table) }
    if(frontHome == 'list') {
        //创建 list
        new File(componentsFile, "List.js" ).withPrintWriter { out -> createListJs(out, name, className, fields, dir, table) }
    } else if (frontHome == 'tree') {
        //创建tree
        new File(componentsFile, "SohoTree.js" ).withPrintWriter { out -> createTreeJs(out, name, className, fields, dir, table) }
    }


    //filter
    new File(componentsFile, "Filter.js" ).withPrintWriter { out -> createFilterJs(out, name, className, fields, dir, table) }
    //Modal
    new File(componentsFile, "Modal.js" ).withPrintWriter { out -> createModalJs(out, name, className, fields, dir, table) }
}

//创建文档相关
def createDoc(out, name, classNmae, fields, dir, table) {
    String[] parts = table.getComment().split(";")
    def tableName = parts[0];
    def tableCapterName = capitalName(name)

    out.println("模块文档")
    out.println("=======")
    out.println("\n\n")
    out.println("添加菜单")
    out.println("-------\n\n")
    out.println("   INSERT INTO `admin_resource` " +
            "(" +
            //"`id`, " +
            "`name`, " +
            "`route`, " +
            "`type`, " +
            "`remarks`, " +
            "`created_time`, " +
            "`visible`, " +
            "`sort`, " +
            "`breadcrumb_parent_id`, " +
            "`zh_name`, " +
            "`icon_name`) " +
            "VALUES " +
            //"(<{id: }>, " +
            "'${tableCapterName}', " +
            "'${name}', " +
            "1," +
            "'${table.getComment()}'," +
            "'2022-01-01 00:00:00'," +
            "1," +
            "100," +
            "0," +
            "'${tableCapterName}'," +
            "'user');")
}

//创建model文件
def generate(out, name,className, fields, dir, table) {
    packageName = findPackageName(dir)
    firstLowClassName = toLowerCaseFirstOne(className)
    def userName = System.getProperty( "user.name")
    //读取表备注
    def tableComment = table.getComment()
    if(tableComment == null || tableComment == '') {
        tableComment = table.getName()
    }
    tableComment = new String(tableComment.getBytes("utf-8"),"gbk");
    if(packageName != "") out.println("package $packageName;\n")

    out.print("import modelExtend from 'dva-model-extend'\n" +
            "import api from 'api'\n" +
            "import { pageModel } from 'utils/model'\n" +
            "const { pathToRegexp } = require(\"path-to-regexp\")\n" +
            "const { query${className}List, update${className}, create${className},delete${className}")

    //循环输出外链表option api
    fields.each() {
        if (it.frontType == 'select' || it.frontType == 'checkbox') {
            if(it.capitalForeignName) {
                def foreignTable = getForeignTableCapitalKey(it.comment)
                out.print(",query${it.capitalForeignName}Options")
            }
        } else if (it.frontType == 'treeSelect') { //tree select
            if(it.capitalForeignName) {
                out.print(",query${it.capitalForeignName}Tree")
            }
        }
    }

    out.println(" } = api\n" +
            "/**\n" +
            " *\n" +
            "   //相关api信息\n" +
            " query${className}List: `GET \${prefix}/admin/${firstLowClassName}/list`,\n" +
            " update${className}: `PUT \${prefix}/admin/${firstLowClassName}`,\n" +
            " create${className}: `POST \${prefix}/admin/${firstLowClassName}`,\n" +
            " delete${className}: `DELETE \${prefix}/admin/${firstLowClassName}/:ids`,\n" +
            " query${className}Details: `GET \${prefix}/admin/${firstLowClassName}/:id`,\n" )

    fields.each() {
        out.println("原始数据解析信息")
        out.print("name: ${it.name}   ")
        out.print("capitalName: ${it.capitalName} ")
        out.print("capitalKeyName: ${it.capitalKeyName}   ")
        out.print("type: ${it.type}   ")
        out.print("frontType: ${it.frontType}     ")
        out.print("frontMax: ${it.frontMax}       ")
        out.print("frontStep: ${it.frontStep}     ")
        out.print("dbType: ${it.dbType}       ")
        out.print("dbUnsigned: ${it.dbUnsigned}       ")
        out.print("comment: ${it.comment}     ")
        out.print("length: ${it.length}       ")
        out.print("scale: ${it.scale}     ")
        out.print("frontLength: ${it.frontLength}     ")
        out.print("defaultValue: ${it.defaultValue}       ")
        out.print("isNotNull: ${it.isNotNull}     ")
        out.print("specification: ${it.specification}     ")
        out.print("dbForeignName: ${it.dbForeignName}     ")
        out.print("capitalForeignName: ${it.capitalForeignName}       ")
        out.print("javaForeignName: ${it.javaForeignName}       ")
    }


    out.println(        " *\n" +
            " */" +
            "\n" +
            "export default modelExtend(pageModel, {\n" +
            "  namespace: '${name}',\n" +
            "  state: {\n" +
            "    options: {"
    )
    fields.each() {
        def frontType = getExtendData(it.comment, 'frontType', 'text')
        if(frontType == 'select' || frontType == 'checkbox') {
            def foreign = getExtendData(it.comment, 'foreign', null)

            out.println(
                    "      ${it.name}: {")
            if(!foreign) {
                def comment = it.comment
                def options = getOptions(comment)
                options.each {entry ->
                    out.println(
                            "           '${entry.key}': '${entry.value}',"
                    )
                }
            }
            out.println("      },")
        }
    }
    out.println(
            "    },\n" +
            "    trees: {")
    //循环输出tree options
    fields.each() {
        if(it.frontType == 'treeSelect') {
            if(it.javaForeignName) {
                out.print("           ${it.javaForeignName}: [],")
            }
        }
    }

    out.println("    }," )

    out.println("  },\n" +
            "\n" +
            "  subscriptions: {\n" +
            "    setup({ dispatch, history }) {\n" +
            "      history.listen(location => {\n" +
            "        if (pathToRegexp('/${name}').exec(location.pathname)) {\n" +
            "          dispatch({\n" +
            "            type: 'query',\n" +
            "            payload: {\n" +
            "              pageSize: 20,\n" +
            "              page: 1,\n" +
            "              ...location.query,\n" +
            "            },\n" +
            "          })")

    fields.each() {
        if (it.frontType == 'select' || it.frontType == 'checkbox') {
            def foreign = getExtendData(it.comment, 'foreign', null)
            if (foreign) {

                out.println(
                        "          dispatch({\n" +
                                "            type: 'query${it.capitalKeyName}Options',\n" +
                                "            payload: {},\n" +
                                "          })"
                )
            }
        } else if(it.frontType == 'treeSelect') {
            if(it.capitalForeignName) {
                out.println(
                        "          dispatch({\n" +
                        "            type: 'query${it.capitalForeignName}Tree',\n" +
                        "            payload: {},\n" +
                        "          })")
            }
        }
    }

    out.println(
            "        }\n" +
            "      })\n" +
            "    },\n" +
            "  },\n" +
            "\n" +
            "  effects: {\n" +
            "    *query({ payload }, { call, put }) {\n" +
            "      const data = yield call(query${className}List, payload)\n" +
            "      if (data.success) {\n" +
            "        yield put({\n" +
            "          type: 'querySuccess',\n" +
            "          payload: {\n" +
            "            list: data.payload.list,\n" +
            "            pagination: {\n" +
            "              current: Number(payload.pageNum) || 1,\n" +
            "              pageSize: Number(payload.pageSize) || 10,\n" +
            "              total: data.payload.total,\n" +
            "            },\n" +
            "          },\n" +
            "        })\n" +
            "      } else {\n" +
            "        throw data\n" +
            "      }\n" +
            "    },\n" +
            "   *create({ payload }, { call, put }) {\n" +
            "      const data = yield call(create${className}, payload)\n" +
            "      if (data.success) {\n" +
            "        yield put({ type: 'hideModal' })\n" +
            "      } else {\n" +
            "        throw data\n" +
            "      }\n" +
            "    },\n" +
            "\n" +
            "    *update({ payload }, { select, call, put }) {\n" +
//            "      const id = yield select(({ user }) => user.currentItem.id)\n" +
//            "      const newUser = { ...payload }\n" +
            "      const data = yield call(update${className}, payload)\n" +
            "      if (data.success) {\n" +
            "        yield put({ type: 'hideModal' })\n" +
            "      } else {\n" +
            "        throw data\n" +
            "      }\n" +
            "    },\n" +
            "    *delete({ payload }, { select, call, put }) {\n" +
            "      const data = yield call(delete${className}, {ids:payload})\n" +
            "      if (!data.success) {\n" +
            "        throw data\n" +
            "      }\n" +
            "    },")
    //TODO 循环输出关联表查询
    fields.each() {
        if(it.frontType == 'select' || it.frontType == 'checkbox') {
            if(it.capitalForeignName) {
                out.println(
                        "    *query${it.capitalKeyName}Options({ payload }, { call, put }) {\n" +
                                "      const data = yield call(query${it.capitalForeignName}Options, payload)\n" +
                                "      if (data.success) {\n" +
                                "        yield put({\n" +
                                "          type: 'queryOptions',\n" +
                                "          payload: {\n" +
                                "              ${it.name}: data.payload\n" +
                                "          },\n" +
                                "        })\n" +
                                "      } else {\n" +
                                "        throw data\n" +
                                "      }\n" +
                                "    },"
                )
            }

        } else if(it.frontType == 'treeSelect') {
            if(it.capitalForeignName) {
                out.println(
                    "   *query${it.capitalForeignName}Tree({payload}, {call, put}) {\n" +
                            "      const data = yield call(query${it.capitalForeignName}Tree, payload);\n" +
                            "      if(data.success) {\n" +
                            "        yield put({\n" +
                            "          type: 'querySuccessTree',\n" +
                            "          payload: {\n" +
                            "            ${it.javaForeignName}: data.payload,\n" +
                            "          }\n" +
                            "        })\n" +
                            "      } else {\n" +
                            "        throw data;\n" +
                            "      }\n" +
                            "   },"
                )

            }
        }

    }
    out.println(        "  },\n" +
            "  reducers: {\n" +
            "    showModal(state, { payload }) {\n" +
            "      return { ...state, ...payload, modalVisible: true }\n" +
            "    },\n" +
            "\n" +
            "    hideModal(state) {\n" +
            "      return { ...state, modalVisible: false }\n" +
            "    },\n" +
            "  },\n" +
            "})")
}

//创建主页 index
def createIndexJs(out, name, className, fields, dir, table) {
    def frontHome = getTableFrontHome(table);
    //写入内容
    out.println("import React, { PureComponent } from 'react'\n" +
            "import PropTypes from 'prop-types'\n" +
            "import {connect, history} from 'umi'\n" +
            "import { stringify } from 'qs'\n" +
            "import { t } from \"@lingui/macro\"\n" +
            "import { Page } from 'components'\n" +
            "import List from './components/List'\n" +
            "import ${className}Modal from \"./components/Modal\";\n" +
            "import Filter from \"./components/Filter\"\n" )
    if(frontHome == 'tree') {
        out.println(
                "import SohoTree from \"./components/SohoTree\";"
        );
    }


    out.println(        "\n" +
            "@connect(({ ${name}, loading }) => ({ ${name}, loading }))\n" +
            "class ${className} extends PureComponent {\n" +
            "  handleRefresh = newQuery => {\n" +
            "    const { location } = this.props\n" +
            "    const { query, pathname } = location\n" +
            "    if(newQuery && newQuery.createTime) {\n" +
            "      newQuery.startDate = newQuery.createTime[0]\n" +
            "      newQuery.endDate = newQuery.createTime[1]\n" +
            "      delete newQuery.createTime\n" +
            "    }\n" +
            "    history.push({\n" +
            "      pathname,\n" +
            "      search: stringify(\n" +
            "        {\n" +
            "          ...query,\n" +
            "          ...newQuery,\n" +
            "        },\n" +
            "        { arrayFormat: 'repeat' }\n" +
            "      ),\n" +
            "    })\n" +
            "  }\n"+
            "  handleTabClick = key => {\n" +
            "    const { pathname } = this.props.location\n" +
            "\n" +
            "    history.push({\n" +
            "      pathname,\n" +
            "      search: stringify({\n" +
            "        status: key,\n" +
            "      }),\n" +
            "    })\n" +
            "  }\n" +
            "\n" +
            "  get listProps() {\n" +
            "    const { ${name}, loading, location, dispatch } = this.props\n" +
            "    const { list, pagination } = ${name}\n" +
            "    const { query, pathname } = location\n" +

            "    return {\n" +
            "      options: ${name}.options,\n" +
            "      trees: ${name}.trees,\n" +
            "      pagination,\n" +
            "      dataSource: list,\n" +
            "      loading: loading.effects['${name}/query'],\n" +
            "      onChange(page) {\n" +
            "        history.push({\n" +
            "          pathname,\n" +
            "          search: stringify({\n" +
            "            ...query,\n" +
            "            page: page.current,\n" +
            "            pageSize: page.pageSize,\n" +
            "          }),\n" +
            "        })\n" +
            "      },\n" +
            "      onDeleteItem: id => {\n" +
            "        dispatch({\n" +
            "          type: '${name}/delete',\n" +
            "          payload: id,\n" +
            "        }).then(() => {\n" +
            "          this.handleRefresh({\n" +
            "            page:\n" +
            "              list.length === 1 && pagination.current > 1\n" +
            "                ? pagination.current - 1\n" +
            "                : pagination.current,\n" +
            "          })\n" +
            "        })\n" +
            "      },\n" +
            "      onEditItem(item) {\n" +
            "        dispatch({\n" +
            "          type: '${name}/showModal',\n" +
            "          payload: {\n" +
            "            modalType: 'update',\n" +
            "            currentItem: item,\n" +
            "          },\n" +
            "        })\n" +
            "      },\n" +
            //TODO 进行树判断
            "      onChildItem(item) {\n" +
            "        dispatch({\n" +
            "          type: 'example_category/showModal',\n" +
            "          payload: {\n" +
            "            modalType: 'create',\n" +
            "            currentItem: {...item},\n" +
            "          },\n" +
            "        })\n" +
            "      }," +
            "    }\n" +
            "  }\n" +
            "\n" +
            "  get modalProps() {\n" +
            "    const { dispatch, ${name}, loading } = this.props\n" +
            "    const { currentItem, modalVisible, modalType,resourceTree,resourceIds } = ${name}\n" +
            "\n" +
            "    return {\n" +
            "      options: ${name}.options,\n" +
            "      trees: ${name}.trees,\n" +
            "      item: modalType === 'create' ? {...currentItem} : currentItem,\n" +
            "      visible: modalVisible,\n" +
            "      destroyOnClose: true,\n" +
            "      maskClosable: false,\n" +
            "      confirmLoading: loading.effects[`${name}/\${modalType}`],\n" +
            "      resourceTree: resourceTree,\n" +
            "      resourceIds: resourceIds,\n" +
            "      title: `\${\n " +
                "        modalType === 'create' ? t`Create` : t`Update`\n" +
                        "      }`,\n" +
                        "      centered: true,\n" +
                        "      onOk: data => {\n" +
                        "        dispatch({\n" +
                        "          type: `${name}/\${modalType}`,\n" +
                        "          payload: data,\n" +
                        "        }).then(() => {\n" +
                        "          this.handleRefresh()\n" +
                        "        })\n" +
                        "      },\n" +
                        "      onCancel() {\n" +
                        "        dispatch({\n" +
                        "          type: '${name}/hideModal',\n" +
                        "        })\n" +
                        "      },\n" +
                        "    }\n" +
                        "  }\n" +
                        "\n" +
                        "  get filterProps() {\n" +
                        "    const { location, dispatch, ${name}} = this.props\n" +
                        "    const {query,pathname} = location\n" +
                        "    return {\n" +
                        "      options: ${name}.options,\n" +
                        "      trees: ${name}.trees,\n" +
                        "      filter: {\n" +
                        "        ...query,\n" +
                        "      },\n" +
                        "      onFilterChange(values) {\n" +
                        "        history.push({\n" +
                        "          pathname,\n" +
                        "          search: stringify(values),\n" +
                        "        })\n" +
                        "      },\n" +
                        "      onAdd() {\n" +
                        "        dispatch({\n" +
                        "          type: '${name}/showModal',\n" +
                        "          payload: {\n" +
                        "            modalType: 'create',\n" +
                        "          },\n" +
                        "        })\n" +
                        "      },\n" +
                        "    }\n" +
                        "  }\n" +
                        "\n" +
                        "  render() {\n" +
                        "    return (\n" +
                        "      <Page inner>\n" )

    if(frontHome == 'list') {
        out.println(
                "        <Filter {...this.filterProps} />\n" +
                        "        <List {...this.listProps} />"
        )
    } else if (frontHome == 'tree') {
        out.println(
                "<SohoTree {...this.listProps} />"
        )
    }

    out.println(
                        "        <${className}Modal {...this.modalProps} />\n" +
                        "      </Page>\n" +
                        "    )\n" +
                        "  }\n" +
                        "}\n" +
                        "\n" +
                        "${className}.propTypes = {\n" +
                        "  ${name}: PropTypes.object,\n" +
                        "  loading: PropTypes.object,\n" +
                        "  location: PropTypes.object,\n" +
                        "  dispatch: PropTypes.func,\n" +
                        "}\n" +
                        "\n" +
                        "export default ${className}\n");
}

//创建列表页 list
def createListJs(out, name, className, fields, dir, table) {
    out.println("import React, { PureComponent } from 'react'\n" +
            "import {Table, Avatar, Modal, Tooltip, Typography} from 'antd'\n" +
            "import {t, Trans} from \"@lingui/macro\"\n" +
            "import { Ellipsis } from 'components'\n" +
//            "import styles from './List.less'\n" +
            "import {DropOption} from \"../../../components\";\n" +
            "import PropTypes from \"prop-types\";\n" +
            "import {getNavigationTreeTitle} from \"../../../utils/tree\";\n" +
            "const { confirm } = Modal\n" +
            "const { Text } = Typography;\n" +
            "\n" +
            "class List extends PureComponent {\n" +
            "  handleMenuClick = (record, e) => {\n" +
            "    const { onDeleteItem, onEditItem } = this.props\n" +
            "\n" +
            "    if (e.key === '1') {\n" +
            "      onEditItem(record)\n" +
            "    } else if (e.key === '2') {\n" +
            "      confirm({\n" +
            "        title: t`Are you sure delete this record?`,\n" +
            "        onOk() {\n" +
            "          onDeleteItem(record.id)\n" +
            "        },\n" +
            "      })\n" +
            "    }\n" +
            "  }\n" +
            "\n" +
            "  render() {\n" +
            "    const { options,trees,...tableProps } = this.props\n" +
            "    const columns = [\n")

            fields.each() {
                def ignoreInList = getExtendData(it.comment, 'ignoreInList', 'false')
                if(ignoreInList == 'false') {
                    out.println(
                            "      {\n" +
                                    "        title: t`${it.frontName}`,\n" +
                                    "        dataIndex: '${it.name}',\n" +
                                    "        key: '${it.name}',"
//                                "        fixed: 'left',"
                    )
                    def frontType = getExtendData(it.comment, 'frontType', 'text')
                    if(frontType == 'select' || frontType == 'checkbox') {
                        out.println(
                                "        render: (text, recode) => {\n" +
                                        "          let map = options.${it.name};" )
                        out.println(
                                "          return map[text]?map[text]:'未知'\n" +
                                        "        },"
                        )
                    } else if(it.type == "String") {
                        out.println(
                                "           render:(text, recode) => {\n" +
                                        "          if(text != null && text.length>60) {\n" +
                                        "            const start = text.slice(0, 120).trim();\n" +
//                                    "            const suffix = text.slice(-20).trim();\n" +
                                        "            return <Text style={{ maxWidth: '100%' }} ellipsis={ \"...\" }>{start}</Text>\n" +
                                        "          } else {\n" +
                                        "            return text\n" +
                                        "          }\n" +
                                        "        }"
                        )
                    } else if(it.frontType == 'treeSelect') {
                        out.println(
                                "        render: (text, recode) => {\n" +
                                        "          return getNavigationTreeTitle(text, trees.${it.javaForeignName})\n" +
                                        "        }"
                        )
                    }
                    out.println(
                            "      },"
                    )
                }

            }

    out.println(

            "      {\n" +
            "        title: <Trans>Operation</Trans>,\n" +
            "        key: 'operation',\n" +
            "        fixed: 'right',\n" +
            "        width: '8%',\n" +
            "        render: (text, record) => {\n" +
            "          return (\n" +
            "            <DropOption\n" +
            "              onMenuClick={e => this.handleMenuClick(record, e)}\n" +
            "              menuOptions={[\n" +
            "                { key: '1', name: t`Update` },\n" +
            "                { key: '2', name: t`Delete` },\n" +
            "              ]}\n" +
            "            />\n" +
            "          )\n" +
            "        },\n" +
            "      },\n" +
            "    ]\n" +
            "\n" +
            "    return (\n" +
            "      <Table\n" +
            "        {...tableProps}\n" +
            "        pagination={{\n" +
            "          ...tableProps.pagination,\n" +
            "          showTotal: (total)=>{return t`Total ` + total + t` Items`},\n" +
            "        }}\n" +
            "        bordered\n" +
            "        scroll={{ x: 1200 }}\n" +
//            "        className={styles.table}\n" +
            "        columns={columns}\n" +
            "        simple\n" +
            "        rowKey={record => record.id}\n" +
            "      />\n" +
            "    )\n" +
            "  }\n" +
            "}\n" +
            "\n" +
            "List.propTypes = {\n" +
            "  onDeleteItem: PropTypes.func,\n" +
            "  onEditItem: PropTypes.func,\n" +
            "  location: PropTypes.object,\n" +
            "}\n" +
            "\n" +
            "export default List\n");
}

//创建Tree首页
def createTreeJs(out, name, className, fields, dir, table) {
    out.println(
            "import React, { PureComponent } from 'react'\n" +
                    "import {Table, Avatar, Modal, Tooltip, Typography, Tree, Input} from 'antd'\n" +
                    "import PropTypes from \"prop-types\";\n" +
                    "import { DownOutlined, PlusOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons';\n" +
                    "import {addRootNode} from \"../../../utils/tree\";\n" +
                    "const { confirm } = Modal\n" +
                    "const { Text } = Typography;\n" +
                    "const { TreeNode } = Tree;\n" +
                    "\n" +
                    "class SohoTree extends PureComponent {\n" +
                    "  map = {}\n" +
                    "  parentList = []\n" +
                    "\n" +
                    "  constructor(props) {\n" +
                    "    super(props);\n" +
//                    "    const {dataSource} = this.props;\n" +
//                    "    const {map, parentList} = this.loadDataFromList(dataSource)\n" +
//                    "    this.state = {dataSource: this.loadTree(0, map, parentList), map,parentList}\n" +
                    "  }\n" +
                    "\n" +
                    "  //编辑选中节点\n" +
                    "  onEdit = (key) => {\n" +
                    "    const { onEditItem } = this.props\n" +
                    "    onEditItem(this.map[key])\n" +
                    "  };\n" +
                    "\n" +
                    "  //删除选中节点\n" +
                    "  onDelete = (key) => {\n" +
                    "    const { onDeleteItem } = this.props\n" +
                    "    onDeleteItem(key)\n" +
                    "  };\n" +
                    "\n" +
                    "  //添加选中节点子结点\n" +
                    "  onAdd = (key) => {\n" +
                    "    const { onChildItem } = this.props\n" +
                    "    onChildItem({parentId: key})\n" +
                    "  };\n" +
                    "\n" +
                    "  onTitleRender = (item) => {\n" +
                    "    return (\n" +
                    "      <div style={{ display: 'flex', alignItems: 'center', height:30 }}>\n" +
                    "\n" +
                    "        <span>\n" +
                    "          {item.title}\n" +
                    "        </span>\n" +
                    "        <span style={{ display: 'flex', marginLeft: 30 }}>\n" +
                    "          <PlusOutlined style={{ marginLeft: 10 }} onClick={() => this.onAdd(item.key)} />\n" +
                    "          {item.key != 0 &&\n" +
                    "            <>\n" +
                    "              <EditOutlined style={{marginLeft: 10}} onClick={() => this.onEdit(item.key)}/>\n" +
                    "              <CloseOutlined style={{marginLeft: 10}} onClick={() => this.onDelete(item.key)}/>\n" +
                    "            </>\n" +
                    "          }\n" +
                    "        </span>\n" +
                    "      </div>\n" +
                    "    );\n" +
                    "  };\n" +
                    "\n" +
                    "  loadTree = (parentId, map, parentList) => {\n" +
                    "    let sons = []\n" +
                    "    if(parentList[parentId] == null) {\n" +
                    "      return sons;\n" +
                    "    }\n" +
                    "    parentList[parentId].map((item)=>{\n" +
                    "      //检查是否有子结点\n" +
                    "      let currentData = {\n" +
                    "        key: item.id,\n" +
                    "        title: item.title\n" +
                    "      }\n" +
                    "      if(parentList[item.id] != null) {\n" +
                    "        currentData['children'] = this.loadTree(item.id, map, parentList)\n" +
                    "      }\n" +
                    "      sons.push(currentData)\n" +
                    "    })\n" +
                    "    return sons;\n" +
                    "  }\n" +
                    "\n" +
                    "  loadDataFromList = (list) => {\n" +
                    "    let map = {}\n" +
                    "    let parentList = {}\n" +
                    "    list.map((item)=>{\n" +
                    "      map[item.id] = item\n" +
                    "      if(parentList[item.parentId] == null) {\n" +
                    "        parentList[item.parentId] = []\n" +
                    "      }\n" +
                    "      parentList[item.parentId].push(item)\n" +
                    "    })\n" +
                    "\n" +
                    "    return {map: map, parentList: parentList}\n" +
                    "    // return this.loadTree(0, map, parentList)\n" +
                    "  }\n" +
                    "\n" +
                    "  render() {\n" +
                    "    const { options,dataSource,...tableProps } = this.props\n" +
                    "    const {map, parentList} = this.loadDataFromList(dataSource)\n" +
                    "    this.map = map\n" +
                    "    this.parentList = parentList\n" +
                    "    return (\n" +
                    "      <div style={{margin:'30 px'}}>\n" +
                    "        <Tree\n" +
                    "          showLine\n" +
                    "          switcherIcon={<DownOutlined />}\n" +
                    "          treeData={addRootNode(this.loadTree(0, map, parentList))}\n" +
                    "          defaultExpandAll={true}\n" +
                    "          titleRender={this.onTitleRender}\n" +
                    "        />\n" +
                    "      </div>\n" +
                    "\n" +
                    "    )\n" +
                    "  }\n" +
                    "}\n" +
                    "\n" +
                    "SohoTree.propTypes = {\n" +
                    "  onDeleteItem: PropTypes.func,\n" +
                    "  onEditItem: PropTypes.func,\n" +
                    "  location: PropTypes.object,\n" +
                    "}\n" +
                    "\n" +
                    "export default SohoTree"
    )
}

//创建过滤器
def createFilterJs(out, name, className, fields, dir, table){

    out.println(
            "import React, { Component } from 'react'\n" +
                    "import PropTypes from 'prop-types'\n" +
                    "import moment from 'moment'\n" +
                    "import { FilterItem } from 'components'\n" +
                    "import { Trans,t } from \"@lingui/macro\"\n" +
                    "import { Button, Row, Col, DatePicker, Form, Input, Cascader, Select } from 'antd'\n" +
                    "\n" +
                    "const { Search } = Input\n" +
                    "const { RangePicker } = DatePicker\n" +
                    "const ColProps = {\n" +
                    "  xs: 24,\n" +
                    "  sm: 12,\n" +
                    "  style: {\n" +
                    "    marginBottom: 16,\n" +
                    "  },\n" +
                    "}\n" +
                    "\n" +
                    "const TwoColProps = {\n" +
                    "  ...ColProps,\n" +
                    "  xl: 96,\n" +
                    "}\n" +
                    "\n" +
                    "class Filter extends Component {\n" +
                    "  formRef = React.createRef()\n" +
                    "\n" +
                    "  handleFields = fields => {\n" +
                    "    const { betweenCreatedTime } = fields\n" +
                    "    if (betweenCreatedTime && betweenCreatedTime.length) {\n" +
                    "      fields.betweenCreatedTime = [\n" +
                    "        moment(betweenCreatedTime[0]).format('YYYY-MM-DD'),\n" +
                    "        moment(betweenCreatedTime[1]).format('YYYY-MM-DD'),\n" +
                    "      ]\n" +
                    "    }\n" +
                    "    return fields\n" +
                    "  }\n" +
                    "\n" +
                    "  handleSubmit = () => {\n" +
                    "    const { onFilterChange } = this.props\n" +
                    "    const values = this.formRef.current.getFieldsValue()\n" +
                    "    const fields = this.handleFields(values)\n" +
                    "    onFilterChange(fields)\n" +
                    "  }\n" +
                    "\n" +
                    "  handleReset = () => {\n" +
                    "    const fields = this.formRef.current.getFieldsValue()\n" +
                    "    for (let item in fields) {\n" +
                    "      if ({}.hasOwnProperty.call(fields, item)) {\n" +
                    "        if (fields[item] instanceof Array) {\n" +
                    "          fields[item] = []\n" +
                    "        } else {\n" +
                    "          fields[item] = undefined\n" +
                    "        }\n" +
                    "      }\n" +
                    "    }\n" +
                    "    this.formRef.current.setFieldsValue(fields)\n" +
                    "    this.handleSubmit()\n" +
                    "  }\n" +
                    "  handleChange = (key, values) => {\n" +
                    "    const { onFilterChange } = this.props\n" +
                    "    let fields = this.formRef.current.getFieldsValue()\n" +
                    "    fields[key] = values\n" +
                    "    fields = this.handleFields(fields)\n" +
                    "    onFilterChange(fields)\n" +
                    "  }\n" +
                    "\n" +
                    "  render() {\n" +
                    "    const { onAdd, filter, options, trees } = this.props\n" +
                    "    const { name } = filter\n" +
                    "\n" +
                    "    let initialCreateTime = []\n" +
                    "    if (filter.createTime && filter.createTime[0]) {\n" +
                    "      initialCreateTime[0] = moment(filter.createTime[0])\n" +
                    "    }\n" +
                    "    if (filter.createTime && filter.createTime[1]) {\n" +
                    "      initialCreateTime[1] = moment(filter.createTime[1])\n" +
                    "    }\n" )
    //初始化options
    fields.each() {
        def frontType = getExtendData(it.comment, 'frontType', 'text')
        if(it.isFilter != 'true') return;
        if(frontType == 'select' || frontType == 'checkbox') {
            out.println(    "    const ${it.name}OptionData = Object.keys(options.${it.name}).map((k,index)=>{" )
            if(it.type == 'String') {
                out.println("      return {value: k, label: options.${it.name}[k]}")
            } else {
                out.println("      return {value: parseInt(k), label: options.${it.name}[k]}")
            }
            out.println(                "    })"
            )
        }
    }

    out.println(                "\n" +
                    "    return (\n" +
                    "      <Form ref={this.formRef} name=\"control-ref\" initialValues={{ name, createdTime: initialCreateTime }}>\n" +
                    "        <Row gutter={24}>\n"
    )
    //输出需要搜索的字段
    fields.each() {
        if(it.name == 'name' || it.name == 'title' || it.name == 'username'
            || it.name == 'orderNo' || it.name == 'trackingNo'
        ) {
            out.println(
                            "          <Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>\n" +
                            "            <Form.Item name=\"${it.name}\">\n" +
                            "              <Search\n" +
                            "                placeholder={t`${it.capitalName}`}\n" +
                            "                onSearch={this.handleSubmit}\n" +
                            "              />\n" +
                            "            </Form.Item>\n" +
                            "          </Col>\n"
            )
        } else if(it.name == 'createdTime') {
            out.println(
                    "          <Col\n" +
                            "            {...ColProps}\n" +
                            "            xl={{ span: 6 }}\n" +
                            "            md={{ span: 8 }}\n" +
                            "            sm={{ span: 12 }}\n" +
                            "            id=\"createTimeRangePicker\"\n" +
                            "          >\n" +
                            "            <FilterItem label={t`${it.capitalName}`}>\n" +
                            "              <Form.Item name=\"between${it.capitalKeyName}\">\n" +
                            "                <RangePicker\n" +
                            "                  style={{ width: '100%' }}\n" +
                            "                />\n" +
                            "              </Form.Item>\n" +
                            "            </FilterItem>\n" +
                            "          </Col>\n"
            )
        } else if(it.isFilter == 'true') {
            if(it.frontType == 'select') {
                out.println(
                        "        <Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>\n" +
                                "            <Form.Item name=\"${it.name}\">\n" +
                        "           <Select\n" +
                                "             showSearch\n" +
                                "             placeholder={t`${it.capitalName}`}\n" +
                                "             optionFilterProp=\"children\"\n" +
                                "             options={${it.name}OptionData}\n" +
                                "             />\n" +
                                "            </Form.Item>\n" +
                                "          </Col>"
                )
            } else {
                out.println(
                        "          <Col {...ColProps} xl={{ span: 4 }} md={{ span: 8 }}>\n" +
                                "            <Form.Item name=\"${it.name}\">\n" +
                                "              <Search\n" +
                                "                placeholder={t`${it.capitalName}`}\n" +
                                "                onSearch={this.handleSubmit}\n" +
                                "              />\n" +
                                "            </Form.Item>\n" +
                                "          </Col>\n"
                )
            }

        }
    }
    out.println(

                    "          <Col\n" +
                    "            {...TwoColProps}\n" +
                    "            xl={{ span: 10 }}\n" +
                    "            md={{ span: 24 }}\n" +
                    "            sm={{ span: 24 }}\n" +
                    "          >\n" +
                    "            <Row type=\"flex\" align=\"middle\" justify=\"space-between\">\n" +
                    "              <div>\n" +
                    "                <Button\n" +
                    "                  type=\"primary\" htmlType=\"submit\"\n" +
                    "                  className=\"margin-right\"\n" +
                    "                  onClick={this.handleSubmit}\n" +
                    "                >\n" +
                    "                  <Trans>Search</Trans>\n" +
                    "                </Button>\n" +
                    "                <Button onClick={this.handleReset}>\n" +
                    "                  <Trans>Reset</Trans>\n" +
                    "                </Button>\n" +
                    "              </div>\n" +
                    "              <Button type=\"ghost\" onClick={onAdd}>\n" +
                    "                <Trans>Create</Trans>\n" +
                    "              </Button>\n" +
                    "            </Row>\n" +
                    "          </Col>\n" +
                    "        </Row>\n" +
                    "      </Form>\n" +
                    "    )\n" +
                    "  }\n" +
                    "}\n" +
                    "\n" +
                    "Filter.propTypes = {\n" +
                    "  onAdd: PropTypes.func,\n" +
                    "  filter: PropTypes.object,\n" +
                    "  onFilterChange: PropTypes.func,\n" +
                    "}\n" +
                    "\n" +
                    "export default Filter\n"
    );
}

//创建编辑页
def createModalJs(out, name, className, fields, dir, table){
    out.println(
            "import React, { PureComponent } from 'react'\n" +
                    "import PropTypes from 'prop-types'\n" +
                    "import {Form, Input, InputNumber, Radio, Modal, Select, Upload, message,Checkbox,DatePicker,TreeSelect} from 'antd'\n" +
                    "import {t, Trans} from \"@lingui/macro\"\n" +
                    "import ImgCrop from \"antd-img-crop\";\n" +
                    "import {LoadingOutlined, PlusOutlined} from \"@ant-design/icons\";\n" +
                    "import moment from 'moment';\n" +
                    "import api from '../../../services/api'\n" +
                    "import store from \"store\";\n" +
                    "import draftToHtml from \"draftjs-to-html\";\n" +
                    "import draft from \"draft-js\";" +
                    "import DraftEditor from \"../../../components/Editor\";" +
                    "import {addRootNode} from \"../../../utils/tree\";\n" +
                    "const {createUserAvatar, createAdminContentImage} = api\n" +
                    "\n" +
                    "const {ContentState} = draft\n" +
                    "const { Option } = Select;\n" +
                    "const FormItem = Form.Item\n" +
                    "//时间格式化\n" +
                    "const datetimeFormat = \"YYYY-MM-DD HH:mm:ss\"\n" +
                    "const dateFormat = \"YYYY-MM-DD\"\n" +
                    "const formItemLayout = {\n" +
                    "  labelCol: {\n" +
                    "    span: 6,\n" +
                    "  },\n" +
                    "  wrapperCol: {\n" +
                    "    span: 14,\n" +
                    "  },\n" +
                    "}\n" +

                    "\n" +
                    "class ${className}Modal extends PureComponent {\n" +
                    "  formRef = React.createRef()\n" +
                    "\n" +
                    "  state = {\n" +
                    "    value: [],\n" +
                    "    loading: false, //上传 loading\n" +
                    "  };\n" +
                    "\n" +

                    "\n" +
                    "  handleOk = () => {\n" +
                    "    const { item = {}, onOk } = this.props\n" +
                    "    this.formRef.current.validateFields()\n" +
                    "      .then(values => {\n" +
                    "        const data = {\n" +
                    "          ...values,\n" +
                    "          id: item.id,")
    out.println("          //时间值处理")
    fields.each() {
        def frontType = it.frontType
        if(frontType == 'datetime' || frontType == 'date') {
            out.println("          ${it.name}: values.${it.name} ? moment(values.${it.name}).format(${frontType}Format) : null,")
        } else if(frontType == 'upload') {
            out.println("          ${it.name}:((values.${it.name}?.fileList || values.${it.name})?.map(value => {\n" +
                    "          if(value.url) return value.url;\n" +
                    "          if(value.response.payload) return value.response.payload;\n" +
                    "         }) || []).join(\";\"),")
        } else  if(frontType == 'editor') {
            out.println(
                    "          ${it.name}:values.${it.name}!=null && values.${it.name} instanceof Object?draftToHtml(values.${it.name}):item.${it.name},"
            )
        }
    }
    out.println(                "        }\n" +
                    "        onOk(data)\n" +
                    "      })\n" +
                    "      .catch(errorInfo => {\n" +
                    "        console.log(errorInfo)\n" +
                    "      })\n" +
                    "  }\n" +
                    "\n" +
                    "  render() {\n" +
                    "    const { item = {}, onOk, form,options,trees, ...modalProps } = this.props\n" )
    //初始化options
    fields.each() {
        def frontType = getExtendData(it.comment, 'frontType', 'text')
        if(frontType == 'select' || frontType == 'checkbox') {
            out.println(    "    const ${it.name}OptionData = Object.keys(options.${it.name}).map((k,index)=>{" )
            if(it.type == 'String') {
                out.println("      return {value: k, label: options.${it.name}[k]}")
            } else {
                out.println("      return {value: parseInt(k), label: options.${it.name}[k]}")
            }
            out.println(                "    })"
            )
        }
    }
    //初始化时间相关参数
    out.print("    let initData = {")
    //初始化默认值
    fields.each() {
         if(it.defaultValue != null && it.defaultValue != null) {
            out.print("${it.name}: ${it.defaultValue},")
        }
    }

    out.println("...item};")
    out.println("    //初始化时间处理")
    fields.each() {
        def frontType = it.frontType
        if(frontType == 'datetime') {
            out.println("    if(item.${it.name}) initData['${it.name}'] = moment(item.${it.name},${frontType}Format)")
        } else if (frontType == 'date') {
            out.println("    if(item.${it.name}) initData['${it.name}'] = moment(item.${it.name},${frontType}Format)")
        } else if (frontType == 'upload') {
            out.println("   initData['${it.name}'] = (initData.${it.name}?.split(';').map((item, key) => {\n" +
                    "        return {\n" +
                    "          uid: -key,\n" +
                    "          key: item,\n" +
                    "          name: item,\n" +
                    "          url: item\n" +
                    "        }\n" +
                    "      }) || []);")
        } else if(it.frontType == 'editor') {
            out.println(
                    "   initData['${it.name}'] = draft.EditorState.createWithContent(ContentState.createFromBlockArray(draft.convertFromHTML(item.${it.name}!=null?item.${it.name}:\"\")));"
            )
        }
    }
    out.println(
                    "    return (\n" +
                    "\n" +
                    "      <Modal {...modalProps} onOk={this.handleOk} width={1300}>\n" +
                    "        <Form ref={this.formRef} name=\"control-ref\" initialValues={{ ...initData }} layout=\"horizontal\">\n"
    );

            fields.each() {
                if(it.name != 'id' && it.name != 'createdTime' && it.name != 'updatedTime') {
                    def maxStr = ""
                    def max = getFrontMax(it)
                    def minStr = ""
                    def min = getFrontMin(it)
                    if(max) {
                        maxStr = ", max: \"${max}\""
                    }
                    if(min != null) {
                        minStr = ", min: \"${min}\""
                    }
                    def ftable = getForeignTableCapitalKey(it.comment)
                    out.println(
                            "         <FormItem  " +
                           //         "frontStep='${it.frontStep}' frontMax='${it.frontMax}' frontLength='${it.frontLength}' l='${it.length}' t='${it.scale}' " +
                                    "name='${it.name}' rules={[{ required: ${it.isNotNull} }]}"
                    )
                    def frontType = it.frontType
                    if(frontType == 'select') {
                        out.println(
                                        "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "           <Select\n" +
                                        "             showSearch\n" +
                                        "             placeholder={t`${it.capitalName}`}\n" +
                                        "             optionFilterProp=\"children\"\n" +
                                        "             options={${it.name}OptionData}\n" +
                                        "             />"
                        )
                    } else if(frontType == 'treeSelect') {
                        out.println(
                                "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "       <TreeSelect\n" +
                                        "             showSearch\n" +
                                        "             style={{ width: '100%' }}\n" +
                                        "             // value={value}\n" +
                                        "             dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}\n" +
                                        "             placeholder=\"Please select\"\n" +
                                        "             allowClear\n" +
                                        "             treeDefaultExpandAll\n" +
                                        "             // onChange={onChange}\n" +
                                        "             treeData={addRootNode(trees?.exampleCategory)}\n" +
                                        "           />"
                        )
                    } else if(frontType == 'checkbox') {
                        out.println(
                                        "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "           <Checkbox.Group\n" +
                                        "             options={${it.name}OptionData}\n" +
                                        "           />"
                        )
                    } else if(frontType == 'datetime' || frontType == 'date') {
                        out.println(
                                        "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "            <DatePicker format={${frontType}Format} showNow showTime={{ format: ${frontType}Format }} />"
                        )
                    } else if(frontType == 'upload') {
                        def uploadCount = getExtendData(it.comment, 'uploadCount', '1')
                        out.println(
                                        "             valuePropName={\"defaultFileList\"} label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "           <Upload listType=\"picture-card\"\n" +
                                        "                   // defaultFileList={defaultFileList}\n" +
                                        "                   name=\"avatar\"\n" +
                                        "                   action={createUserAvatar}\n" +
                                        "                   // onChange={this.handleChange}\n" +
                                        "                   headers={{Authorization:store.get('token')}}\n" +
                                        "                   maxCount={${uploadCount}}>\n" +
                                        "             <div>\n" +
                                        "               <PlusOutlined />\n" +
                                        "               <div style={{ marginTop: 8 }}>Upload</div>\n" +
                                        "             </div>\n" +
                                        "           </Upload>"
                        )
                    } else if(frontType == 'number') {
                        out.print(
                                "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "            <InputNumber" )
                        //校验规则
//                        if(min) out.print(" minLenght={${min}}")
//                        if(max) out.print(" maxLength={${max}}")
                        if(it.frontMax) out.print(" max={${it.frontMax}}")
                        if(it.frontStep) out.print(" step=\"${it.frontStep}\"")
                        out.print("  style={{width:200}}")
                        out.println(" />")
                    } else if (frontType == 'editor') {
                        out.println(
                                "           label={t`${it.frontName}`} valuePropName={\"defaultEditorState\"} hasFeedback {...formItemLayout}>\n" +
                                        "           <DraftEditor\n" +
                                        "             // defaultEditorState={${it.name}\n" +
                               //         "             //editorClassName={style.sohoEdit}\n" +
                                        "             toolbar={{\n" +
                                        "               image: {\n" +
                                        "                 urlEnabled: true,\n" +
                                        "                 // uploadEnabled: true,\n" +
                                        "                 alignmentEnabled: true,   // 是否显示排列按钮 相当于text-align\n" +
                                        "                 // uploadCallback: this.upload,\n" +
                                        "                 // previewImage: true,\n" +
                                        "                 // inputAccept: 'image/*',\n" +
                                        "                 alt: {present: false, mandatory: false,previewImage: true}\n" +
                                        "               },\n" +
                                        "             }}\n" +
                                        "           />"
                        )
                    } else if(frontType == 'password') {
                        out.print(
                                "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "            <Input.Password" )
                        //校验规则
                        if(min) out.print(" minLenght={${min}}")
                        if(max) out.print(" maxLength={${max}}")
                        out.println(" />")
                    } else {
                        out.print(
                                        "            label={t`${it.frontName}`} hasFeedback {...formItemLayout}>\n" +
                                        "            <Input" )
                        //校验规则
                        if(min) out.print(" minLenght={${min}}")
                        if(max) out.print(" maxLength={${max}}")
                                                out.println(" />")

                    }
                    out.println("          </FormItem>")
                }
            }

out.println(                    "        </Form>\n" +
                    "      </Modal>\n" +
                    "    )\n" +
                    "  }\n" +
                    "}\n" +
                    "\n" +
                    "${className}Modal.propTypes = {\n" +
                    "  type: PropTypes.string,\n" +
                    "  item: PropTypes.object,\n" +
                    "  onOk: PropTypes.func,\n" +
                    "}\n" +
                    "\n" +
                    "export default ${className}Modal\n"
    );
}

////////////////////////////////// 以下为公共函数

//def create
def calcFields(table) {
    DasUtil.getColumns(table).reduce([]) { fields, col ->
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())
        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        def dbTypeStr = dbTypeMapping.find { p, t -> p.matcher(spec).find() }.value
        def isUnsignedMatch = dbUnsignedMapping.find {p, t -> p.matcher(spec).find() }
        def isUnsigned = isUnsignedMatch == null ? false : true
        def frontType = getFrontType(dbTypeStr, col.getComment())
        def frontMax = new BigDecimal("0")
        def frontStepStr = ""
        //外链表信息
        def dbForeignName = "";
        def capitalForeignName = "";
        def javaForeignName = "";
        def javaType = getJavaType(dbTypeStr, col.getComment())
        def isFilter = getExtendData(col.getComment(), 'isFilter', 'false');
        def frontName = capitalName(getExtendData(col.getComment(), 'frontName', ''))
        if(frontName == '') {
            frontName = capitalName(col.getName());
        }

        if(frontType == 'select' || frontType == 'treeSelect') {
            dbForeignName = getForeignTable(col.getComment())
            if(dbForeignName) {
                capitalForeignName = capitalName(dbForeignName).replace(" ", "")
                javaForeignName =  javaName(dbForeignName, false)
            }
        }

        if(frontType == 'number') {
            //计算最大值
            frontMaxStr = String.format("%1\$" + (col.getDataType().getLength() - ((col.getDataType().getScale()>0)?col.getDataType().getScale() : 0)) + "s", "9").replace(' ', '9')
            if(col.getDataType().getScale()>0) {
                frontMaxStr += "."+String.format("%1\$" + (col.getDataType().getScale()) + "s", "9").replace(' ', '9')
            }
            frontMax = new BigDecimal(frontMaxStr);
            //计算step
            if(col.getDataType().getScale()>0) {
                frontStepStr = "0."+String.format("%1\$" + (col.getDataType().getScale()) + "s", "1").replace(' ', '0')
            }
        } else {
            frontMax = null
        }


        fields += [[
                           name : javaName(col.getName(), false), //小驼峰名称
                           capitalName: capitalName(col.getName()), //带空格的大驼峰名称
                           capitalKeyName: capitalName(col.getName()).replace(" ", ""), //大驼峰名称
                           dbColName: col.getName(), //db原始名称
                           type : typeStr, //对应的java数据了些
                           frontType: frontType, //
                           frontName: frontName, //前端展示名称
                           frontMax: frontMax, //前端展示最大数
                           frontStep: frontStepStr, //前端数字展示 step
                           isFilter: isFilter, //是否为列表页条件筛选字段
                           dbType: dbTypeStr, //数据库类型
                           dbUnsigned: isUnsigned, //数据库字段为无符号类型
                           comment: col.getComment(), //字段注释
                           annos: "",  //？？
                           length: col.getDataType().getLength(), //字段长度
                           scale: col.getDataType().getScale(), //小数部分长度
                           frontLength: (frontType == 'number') ? col.getDataType().getLength() + 1 : col.getDataType().getLength(), //前端校验长度
                           defaultValue: col.getDefault(), //字段默认值
                           isNotNull: col.isNotNull(), //是否可以为空
                           specification: col.getDataType().getSpecification(), //只用来做调试，请勿使用
                           dbForeignName: dbForeignName, //外建db名
                           capitalForeignName: capitalForeignName, //外建大驼峰
                           javaForeignName: javaForeignName, //java外链表名
                           javaType: javaType, //字段对应的java类型
                   ]]
    }
}

def javaName(str, capitalize) {
    if(str  == null) {
        return null;
    }
    def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
            .collect { Case.LOWER.apply(it).capitalize() }
            .join("")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
    capitalize || s.length() == 1? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def capitalName(str) {
    if(str == null) {
        return null;
    }
    com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
            .collect { Case.LOWER.apply(it).capitalize() }
            .join(" ")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, " ")
}

/**
 * 获取前端类型
 *
 * @param dbType
 * @param comment
 * @return
 */
def getFrontType(dbType, comment) {
    def frontType = getExtendData(comment, 'frontType', null);
    if(frontType) {
        return frontType;
    }
    switch (dbType) {
        case "int":
        case "tinyint":
        case "smallint":
        case "mediumint":
        case "bigint":
        case "float":
        case "double":
        case "decimal":
            frontType = "number"
            break;
        default:
            frontType = "text";
            break;
    }
    return frontType;
}

/**
 * 获取外链表
 *
 * @param comment
 * @return
 */
def getForeignTable(comment) {
    def foreign = getExtendData(comment, 'foreign', null)
    if(foreign) {
        String[] parts = foreign.split("~")
        if(parts && parts.length>=1) {
            def fid = parts[0]
            String[] tableParts = fid.split("\\.")
            if(tableParts.length>0) {
                return tableParts[0]
            }
        }
    }
    return null;
}

/**
 * 获取关联表大驼峰名
 */
def getForeignTableCapitalKey(comment) {
    def capita = getForeignTable(comment)
    if(capita) {
        return capitalName(capita).replace(" ", "");
    }
    return null;
}

/**
 * 获取前端校验最小值
 */
def getFrontMin(it) {
    def min = 0
    def minStr = getExtendData(it.comment,"min", null)
    if(minStr != null) {
        return Integer.valueOf(minStr)
    }

    //检查表单类型
    def frontType = getExtendData(it.comment, 'frontType', 'text')
    if(frontType != 'text') {
        return null;
    }

    if(it.dbUnsigned) {
        //无符号
        switch (it.dbType) {
            case "tinyint":
            case "smallint":
            case "mediumint":
            case "int":
            case "bigint":
                min = 0;
                break;
            default:
//                min = it.length;
                break;
        }
    } else {
        switch (it.dbType) {
            case "tinyint":
                min = -128
                break;
            case "smallint":
                min = -32768;
                break;
            case "mediumint":
                min = 	-8388608;
                break;
            case "int":
                min = -2147483648;
                break;
            case "bigint":
                min = -9007199254740991;  //该值为Js最大值
                break;
            default:
//                min = it.length;
                break;
        }
    }
    return min;
}

/**
 * 获取前端校验最小值
 */
def getFrontMax(it) {
    def max = it.length
    //dbUnsigned
    def maxStr = getExtendData(it.comment,"max", null)
    if(maxStr != null) {
        //如果指定直接使用指定值
        return Integer.valueOf(maxStr)
    }

    //检查表单类型
    def frontType = getExtendData(it.comment, 'frontType', 'text')
    if(frontType != 'text') {
        return null;
    }

    if(it.dbUnsigned) {
        //无符号
        switch (it.dbType) {
            case "tinyint":
                max = 255
                break;
            case "smallint":
                max = 	65535;
                break;
            case "mediumint":
                max = 16777215;
                break;
            case "int":
                max = 4294967295;
                break;
            case "bigint":
                max = 9007199254740992;  //该值为Js最大值
                break;
            default:
                max = it.length;
                break;
        }
    } else {
        switch (it.dbType) {
            case "tinyint":
                max = 127
                break;
            case "smallint":
                max = 32767;
                break;
            case "mediumint":
                max = 8388607;
                break;
            case "int":
                max = 2147483647;
                break;
            case "bigint":
                max = 9007199254740992;  //该值为Js最大值
                break;
            default:
                max = it.length;
                break;
        }
    }

    return max;
}

/**
 * 查找domain命名空间
 *
 * @param dir
 */
def findDomainPackageName(dir) {
    return findPackageName(new File(dir.getParent() + "/domain"))
}

/**
 * 查找service命名空间
 *
 * @param dir
 */
def findServicePackageName(dir) {
    return findPackageName(new File(dir.getParent() + "/service"))
}

/**
 * 查找指定目录现有的命名空间
 *
 * @param dir
 * @return
 */
def findPackageName(dir) {
    if(dir != null && dir.isDirectory()) {
        File[] files = dir.listFiles();
        if(files != null && files.length>0) {
            for (File item:files) {
                if(item.isFile()) {
                    List<String> lines = Files.readLines(item, StandardCharsets.UTF_8);
                    //查找命名空间
                    for (String line: lines) {
                        line = line.trim();
                        if(line.startsWith("package")) {
                            line = line.split(" ")[1];
                            line = line.replace(";", "")
                            line = line.trim();
                            return line;
                        }
                    }
                }
            }
        }
    }
    return ""
}

/**
 * 首字母小写
 * @param s
 * @return
 */
def toLowerCaseFirstOne(String s){
    if(Character.isLowerCase(s.charAt(0)))
        return s;
    else
        return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
}

/**
 * 转换成中划线
 *
 * @param s
 * @return
 */
def toStrikethrough(String str) {
    def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
            .collect { Case.LOWER.apply(it) }
            .join("-")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
    return s
}

/**
 * 获取当前时间
 * @return
 */
def currentDate() {
    Date d = new Date();
    System.out.println(d);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String dateNowStr = sdf.format(d);
    return dateNowStr;
}

/**
 * 获取注解选项
 *
 * @param comment
 * @return
 */
def getOptions(String comment) {
    if(comment == null) {
        return []
    }
    String[] parts = comment.split(";");
    if(parts.length<2) {
        return null;
    }
//    String colmenName = parts[0];
    parts = parts[1].split(",");
    HashMap<String, String> dataMap = new HashMap<>();
    for (String item: parts) {
        String[] kv = item.split(":");
        if(kv.length == 2) {
            dataMap.put(kv[0].trim(), kv[1]);
        } else {
            dataMap.put(kv[0], kv[0]);
        }
    }
    return dataMap;
}

/**
 * 获取前端展示类型
 *"frontType"
 * @param comment
 */
def getExtendData(String comment, String key, String defaultVal) {
    String type = defaultVal
    if(comment == '' || comment == null) {
        return defaultVal
    }
    String[] parts = comment.split(";");
    if(parts.length<3) {
        return type;
    }
    if(parts.length>=3) {
        parts = parts[2].split(",");
        HashMap<String, String> dataMap = new HashMap<>();
        for (String item: parts) {
            String[] kv = item.split(":");
            if(kv.length == 2) {
                dataMap.put(kv[0].trim(), kv[1]);
            }
        }
        if(dataMap.containsKey(key)) {
            type = dataMap.get(key)
        }
    }
    return type
}

/**
 * 获取表前端首页类型
 *
 * @param table
 * @return
 */
def getTableFrontHome(table) {
    def fontType = getExtendData(table.getComment(), 'frontHome', 'list')
    return fontType;
}

/**
 * 获取制定字段类型
 *
 * @param name
 * @param fileds
 */
def getCol(name, fileds) {
    def col = null;
    fileds.each() {
        if(name == it.dbColName) {
            col = it;
        }
    }
    return col;
}

/**
 * 获取表选项key
 *
 * @param comment
 * @param fileds
 * @return
 */
def getOptionKeyCol(comment, fileds) {
    def optionStr = getExtendData(comment, 'option', null)
    if(optionStr == null) {
        return null
    }
    String[] parts = optionStr.split("~")
    if(parts.length>0)  {
        def col = getCol(parts[0], fileds)
        if(col == null) {
            return null;
        }
        return col;
    }
    return null;
}

/**
 * 获取表选项key
 *
 * @param comment
 * @param fileds
 * @return
 */
def getOptionValCol(comment, fileds) {
    optionStr = getExtendData(comment, 'option', null)
    if(optionStr == null) {
        return null
    }
    String[] parts = optionStr.split("~")
    if(parts.length>1)  {
        def col = getCol(parts[1], fileds)
        if(col == null) {
            return null;
        }
        return col;
    }
    return null;
}

/**
 * 根据字段类型注解获取java类型
 *
 * @param dbType
 * @param comment
 */
def getJavaType(dbType, comment) {
    def javaType = getExtendData(comment, "javaType", null)
    if(javaType != null)  {
        return javaType
    }
    //查看注解有没有指定后段类型
    switch (dbType) {
        case 'int':
        case 'tinyint':
        case 'smallint':
        case 'mediumint':
            javaType = "Integer"
            break;
        case 'bigint':
            javaType = "BigInteger"
            break;
        case 'bit':
            javaType = 'Boolean'
            break;
        case 'data':
        case 'datetime':
        case 'timestamp':
            javaType = "LocalDateTime"
            break;
        case 'float':
            javaType = "Float"
            break
        case 'double':
            javaType = "Double"
            break;
        default:
            javaType = "String"
            break;
    }
    return javaType
}
